#pragma once

#include <iostream>
#include <set>
#include <string.h>
#include <unistd.h>
#include <sys/epoll.h>


namespace EpollerModule{
    const int defaultepfd = -1;
    const int size = 128;

    enum {
        CreateError = 4
    };

    class Epoller{
        public:
            Epoller(int epfd = defaultepfd) :_epfd(epfd) {}
            ~Epoller() {
                if(_epfd > defaultepfd) 
                    close(_epfd);
                std::cout << "close epfd success!!!" << std::endl;
            }

            void InitEpoller() {
                _epfd = ::epoll_create(size);
                if(_epfd == defaultepfd) {
                    std::cout << "epoll_create error, " << strerror(errno) << ": " << errno << std::endl;
                    exit(CreateError);
                }
                std::cout << "epoll_create success, epfd: " << _epfd << std::endl;
            }

            void AddEvent(int sockfd, uint32_t events) {
                fd_list.insert(sockfd);

                struct epoll_event ev;
                ev.events = events;
                ev.data.fd = sockfd;

                int n = ::epoll_ctl(_epfd, EPOLL_CTL_ADD, sockfd, &ev);
                if(n < 0) 
                    std::cout << "epoll_ctl add error, " << strerror(errno) << ": " << errno << std::endl;
            }

            void DelEvent(int sockfd) {
                fd_list.erase(sockfd);

                int n = ::epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr);
                if(n < 0)
                    std::cout << "epoll_ctl del error, " << strerror(errno) << ": " << errno << std::endl;
            }

            void DebugFdList() {
                std::cout << "fd_list: ";
                for(auto fd : fd_list) {
                    std::cout << fd << " ";
                }
                std::cout << std::endl;
            }

            int Wait(struct epoll_event *events, int maxevents, int timeout) {
                int n = ::epoll_wait(_epfd, events, maxevents, timeout);
                return n;
            }
        private:
            int _epfd;              // epoll模型的文件描述符
            std::set<int> fd_list;  // 用于跟踪当前被epoll监控的文件描述符集合，文件描述符递增(不重复)
    };
}